#include "Logger.h"
#include <sstream>
#include <Windows.h>

FILE* Logger::logFile;
string Logger::logFileName;
string Logger::filepath;
string Logger::archive;
time_t Logger::logtime;
tm* Logger::now;
int Logger::maxlines;
short Logger::logLevel;

int Logger::Initialize(short logLev, string logFile) {
	Logger::logFile = NULL;
	Logger::now = NULL;
	Logger::logLevel = logLev;
	Logger::maxlines = 100;
	Logger::archive = "Logs";

	Logger::SetLogfile(logFile);
	Logger::CheckLogFileSize();


	if(logFile == "Default.log") {
		ostringstream message;

		Logger::logtime = time(0);
		Logger::now = localtime(&Logger::logtime);

		message << "==================================================================================================================" << endl;
		message << "->" << Logger::now->tm_hour << ":" << Logger::now->tm_min << ":" << Logger::now->tm_sec << " START" << endl;
		message << "==================================================================================================================" << endl;

		Logger::WriteLog(message.str());
	}

	return NO_ERRORS;
}

int Logger::Shutdown() {

	if(Logger::logFileName == "Default.log") {

		ostringstream message;

		Logger::logtime = time(0);
		Logger::now = localtime(&Logger::logtime);

		message << "==================================================================================================================" << endl;
		message << "->" << Logger::now->tm_hour << ":" << Logger::now->tm_min << ":" << Logger::now->tm_sec << " STOP" << endl;
		message << "==================================================================================================================" << endl;
		message << "\n\n\n\n\n\n\n";

		Logger::WriteLog(message.str());
	}

	if(Logger::logFile != NULL) fclose(Logger::logFile);

	return 0;
}

void Logger::Log(int errorCode, string message, string file, int line, short errorType) {

	if(Logger::logLevel >= LOG_ERRORS) {
		// Log errors
		
		ostringstream tmpMessage;
		ostringstream errorCodeStr;
		Logger::logtime = time(0);
		Logger::now = localtime(&Logger::logtime);

		if(errorType == LOG_ERROR) {
			if(errorCode != 0) errorCodeStr << " - Code: " << errorCode;
			tmpMessage << "(" << Logger::now->tm_hour << ":" << Logger::now->tm_min << ":" << Logger::now->tm_sec << ") ERROR" << errorCodeStr.str() << " (" << file << " on line " << line << "): " << message << endl;
			Logger::WriteLog(tmpMessage.str());
		}

		if(Logger::logLevel >= LOG_WARNINGS) {
			// Log Warnings

			if(errorType == LOG_WARNING) {
				if(errorCode != 0) errorCodeStr << " - Code: " << errorCode;
				tmpMessage << "(" << Logger::now->tm_hour << ":" << Logger::now->tm_min << ":" << Logger::now->tm_sec << ") WARNING" << errorCodeStr.str() << " (" << file << " on line " << line << "): " << message << endl;
				Logger::WriteLog(tmpMessage.str());
			}

			if(Logger::logLevel >= LOG_NOTICES) {
				// Log Notices

				if(errorType == LOG_NOTICE) {
					if(errorCode != 0) errorCodeStr << " - Code: " << errorCode;
					tmpMessage << "(" << Logger::now->tm_hour << ":" << Logger::now->tm_min << ":" << Logger::now->tm_sec << ") NOTICE" << errorCodeStr.str() << " (" << file << " on line " << line << "): " << message << endl;
					Logger::WriteLog(tmpMessage.str());
				}
			}
		}
	}
}

void Logger::Log(string message, string file, int line) {
	if(Logger::logLevel >= LOG_NOTICES) {
		ostringstream tmpMessage;
		Logger::logtime = time(0);
		Logger::now = localtime(&Logger::logtime);

		tmpMessage << "(" << Logger::now->tm_hour << ":" << Logger::now->tm_min << ":" << Logger::now->tm_sec << ") NOTICE (" << file << " on line " << line << "): " << message << endl;
		Logger::WriteLog(tmpMessage.str());
	}
}

void Logger::WriteLog(string message) {
	Logger::CheckLogFileSize();
	fputs(message.c_str(), Logger::logFile);
	fflush(Logger::logFile);
}

void Logger::SetLogfile(string file) {
	ostringstream tmpFilePath;

	Logger::logFileName = file;

	if(Logger::logFile != NULL) fclose(Logger::logFile);

	Logger::logtime = time(0);
	Logger::now = localtime(&Logger::logtime);

	tmpFilePath << Logger::now->tm_mday << "-" << Logger::now->tm_mon + 1 << "-" << Logger::now->tm_year + 1900 << "." << file;
	Logger::filepath = tmpFilePath.str();

	Logger::logFile = fopen(Logger::filepath.c_str(), "a+");
}

void Logger::CheckLogFileSize() {
	char line[1000];
	int lines = 0;

	rewind(Logger::logFile);
	while(fgets(line, 1000, Logger::logFile) != NULL) lines++;

	if(lines >= Logger::maxlines) Logger::RotateLogFiles();
}

// Moves full LogFiles to the archive
void Logger::RotateLogFiles() {
	if(Logger::logFile != NULL) fclose(Logger::logFile);
	int i = 0;
	ostringstream newpath;
	string tmp;
	Logger::logtime = time(0);
	Logger::now = localtime(&Logger::logtime);

	newpath << Logger::archive << "\\" << Logger::now->tm_mday << "-" << Logger::now->tm_mon + 1 << "-" << Logger::now->tm_year + 1900 << "\\" << Logger::now->tm_hour << "_" << Logger::now->tm_min << "_" << Logger::now->tm_sec << "-" << Logger::filepath.substr(Logger::filepath.find(".")+1, string::npos);
	boost::filesystem::path abs_oldpath = boost::filesystem::complete(Logger::filepath);
	boost::filesystem::path abs_newpath = boost::filesystem::complete(newpath.str());
	boost::filesystem::create_directories(abs_newpath.branch_path());

	while(boost::filesystem::exists(abs_newpath)) {
		if(i == 0) tmp = newpath.str().erase(newpath.str().find(".log"), string::npos);
		newpath.str("");
		newpath.clear();
		i++;
		newpath << tmp << "." << i << ".log";
		abs_newpath = boost::filesystem::complete(newpath.str());
	}

	if(!MoveFile((TCHAR*)abs_oldpath.c_str(), (TCHAR*)abs_newpath.c_str())) {
		char* msg;
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msg, 0, NULL);
		MessageBox(NULL, (TCHAR*)msg, L"Error", MB_OK | MB_ICONERROR);
	}
	else boost::filesystem::remove(abs_oldpath);

	Logger::logFile = fopen(Logger::filepath.c_str(), "a+");
}